[2025-07-10] SOP&CORS

🦥 본문

SOP

정의

Same Origin Policy. 동일 출처 정책. 서로 다른 출처의 웹페이지 간에는 서로의 리소스에 접근할 수 없도록 제한하는 보안 정책. 데이터 쓰기는 가능하다.

  • 출처 : 프로토콜 + 도메인 + 포트 이며, 구성 요소가 모두 일치해야 같은 출처이다.

CORS

Cross Origin Resource Sharing. 교차 출처 리소스 공유. 다른 출처의 데이터를 처리하기 위해 SOP를 완화

  • Cross Origin Resource Sharing(교차 출처 리소스 공유)
  • 여기서 출처라는 것은 프로토콜,도메인,포트로 구성되어 있으며 기본적으로는 Same-Origin Policy로 이 중 하나라도 다르면 CORS 에러를 만나게 됨
  • HTTP 메서드와 헤더들에 정보를 포함되어 있다

동작 흐름

image.png

  • 예비 요청(Preflight Request) : 서버에게 이런 방식을 사용해도 괜찮은 지 확인하는 것
    1. JS에서 request을 보냄
    2. 브라우저에서 서버 쪽에 예비 요청을 보냄. 예비 요청은 OPTIONS 메소드를 통해 전송되며, Origin, Access-Control-Requset-Method, Access-Control-Request-Headers 등의 헤더만 있고 바디에는 아무 것도 작성하지 않는다. Access-Control-Request-Headers는 커스텀 헤더임
    3. 서버 쪽에서 허용/거절에 관한 예비 응답을 보내게 됨.
    4. 허용을 하게 되면 원래 요청을 보내고 응답을 받음. 허용되지 않는 경우 에러를 발생시키고 원래 요청은 서버로 전송하지 않는다.

image.png

  • 단순 요청(Simple Request) : 예비 요청을 생략하고 바로 서버에 요청을 보냄. 응답의 헤더에 Access-Control-Allow-Origin 헤더를 통해 CORS 정책 위반 여부를 검사. 다음과 같은 조건을 만족해야 함.
    • 요청 메소드가 GET, HEAD, POST 중 하나
    • Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width 헤더일 경우에만 적용
    • Content-Type: application/x-www-form-urlencoded, text/plain, multipart/form-data 중 하나

인증 방법

  • Client 측
fetch('https://api.example.com', {
  credentials: 'include'
});

axios.get('https://api.example.com', {
  withCredentials: true
})
  • Sever 측
Access-Control-Allow-Credentials:
Access-Control-Allow-Origin:
Access-Control-Allow-Methods:
Access-Control-Allow-Headers:
  • Access-Control-Allow-Origin 헤더를 설정하여 요청을 수락할 출처를 명시적으로 지정할 수 있다.
  • 브라우저가 임의의 웹 페이지에서 다른 웹 페이지의 자원에 무분별하게 접근을 막고 필요한 경우 특정 출처에 대해서만 리소스 접근을 허용하여 유연성이 생김
  • 잘못된 방법으로 사용하면 보안적으로 취약해진다.i

공격 방법

image.png

  • Credential을 탈취해서 악성 서버에서 다른 중요 정보를 탈취하는 경우. CORS 정책을 통해 쿠키나 세션을 탈취당해도 다른 정보들을 접근하지 못하게 한다.
  • 와일드카드(*) 출처 사용
    • 모든 출처를 허용하기 때문에 보안이 취약해진다.
    • 브라우저에서 Credential : true. 즉, 인증 정보를 주고 받는 경우에는 와일드 카드를 불가능하게 하였다.
  • 위의 방식을 피하려고 대신에 request 객체의 Origin 헤더 값을 가져와서 그대로 Acess-Control-Allow-Origin값에 넣는 방식
  • Origin에 null을 넣는 방식
    • iframe을 통한 요청은 null Origin
      • iframe : HTML 문서 안에 다른 웹페이지를 삽입할 수 있게 해주는 태그, sandbox 속서을 통해 출처를 제거할 수 있음(null)
      • 악성 서버에서 fetch를 통해 해당 서버에 대한 클라이언트의 쿠키나 세션을 들고 요청을 보냄. 이때 Origin: null을 설정했다면, 공격자 서버에 응답이 도착할 수 있음

해결 방법

  • wildcard 서브 도메인 허용 : 클라이언트가 너무 많은 경우, 특정한 패턴을 따른다면 해당 도메인의 신뢰할 수 있는 서브 도메인인지 검사하는 방식.
    • 우회할 수 있는 가능성이 있기 때문에 화이트리스트보다는 위험함
  • 화이트리스트 : 배열이나 리스트에 허용할 출처들을 저장해놓고 관리하여 검사하는 방식. 가장 안전한 방법

JSONP

정의

JSON with Padding. 브라우저의 스크립트 태그는 SOP 제한을 받지 않는 점을 이용하여 서버에서 JSON 데이터를 받아오는 방식의 기술

작동 방식


---

1. 서버는 `callback` 파라미터를 꺼

callback = ‘handleData’

@app.route(‘/data’) def jsonp(): data = {‘name’: ‘윤서’, ‘age’: 22} callback = request.args.get(‘callback’) # ← 여기서 callback 파라미터 읽음 response_text = f”{callback}({data})” # 함수 호출 형태로 감쌈 return make_response(response_text, 200, {‘Content-Type’: ‘application/javascript’})


그리고 JSON 데이터를 이 함수에 **감싸서 응답 문자열을 만듦**:

handleData({ “name”: “윤서”, “age”: 22 });


그리고 이걸 브라우저에 돌려보냄.

---

3.  브라우저는 응답을 `<script>`처럼 **자동 실행**

브라우저는 `<script>` 태그로 응답을 받았기 때문에,

아래 코드를 마치 원래 웹페이지에 있던 JS 코드처럼 **실행**해버림:

handleData({ “name”: “윤서”, “age”: 22 })


---

4.  클라이언트 측에 이미 정의된 함수가 호출됨

클라이언트가 미리 이 함수를 만들어뒀다면:

```html
<script>
  function handleData(data) {
    console.log("서버에서 온 데이터:", data);
  }
</script>

서버가 보낸 응답이 브라우저가 만든 스크립트 코드처럼 실행되면서 콜백 함수가 자동으로 실행되는 것

Categories:

Updated:

Leave a comment